<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\CustHub\Constants\OpSchemeTypeConstants;
use App\CustHub\Constants\RoomInviteLogTypeConstants;
use App\CustHub\Constants\SendConfigConstants;
use App\CustHub\Helpers\TagReplacer;
use App\CustHub\Mapper\ChContactMapper;
use App\CustHub\Mapper\ChOpSchemeMapper;
use App\CustHub\Mapper\ChOpSchemeRobotMapper;
use App\CustHub\Mapper\ChRobotMapper;
use App\CustHub\Mapper\ChRoomInviteActiveRoomMapper;
use App\CustHub\Model\ChContact;
use App\CustHub\Model\ChEmployee;
use App\CustHub\Model\ChOpScheme;
use App\CustHub\Model\ChOpSchemeRobot;
use App\CustHub\Model\ChRobot;
use App\CustHub\Model\ChRoom;
use App\CustHub\Model\ChRoomInviteActiveRoom;
use App\CustHub\Model\ChRoomInviteLog;
use App\CustHub\Model\ChRoomInviteSendTask;
use App\CustHub\Traits\OpSchemeTrait;
use App\Robot\Dto\CommonJobDto;
use App\Robot\Job\CommonJob;
use Carbon\Carbon;
use FriendsOfHyperf\Lock\Exception\LockTimeoutException;
use Hyperf\Database\Model\Builder;
use Hyperf\Database\Model\Model;
use Hyperf\Di\Annotation\Inject;
use Mine\Abstracts\AbstractService;
use Mine\Annotation\DeleteCache;
use Mine\Annotation\Transaction;
use Mine\Exception\NormalStatusException;
use function FriendsOfHyperf\Lock\lock;
use function Hyperf\Collection\collect;
use function Hyperf\Collection\data_get;
use function Hyperf\Coroutine\co;
use function Hyperf\Support\optional;


/**
 * 关键词拉群
 */
class ChRoomKeywordService extends AbstractService
{
    use OpSchemeTrait;

    public $mapper;

    protected int $type = OpSchemeTypeConstants::ROOM_KEYWORD;

    #[Inject]
    protected ChOpSchemeRobotMapper $schemeRobotMapper;

    #[Inject]
    protected ChContactMapper $contactMapper;

    #[Inject]
    protected ChRobotMapper $robotMapper;

    #[Inject]
    protected ChRoomInviteActiveRoomMapper $inviteActiveRoomMapper;

    public function __construct(ChOpSchemeMapper $mapper)
    {
        $this->mapper = $mapper;
    }


    public function handleSearch(Builder $query, array $params): Builder
    {
        $name = data_get($params, 'name');
        $type = data_get($params, 'type');


        if(!empty($name)){
            $query->where('name','like',$name.'%');
        }

        if(filled($type)){
            $query->whereRaw("JSON_EXTRACT(`cfg`, '$.type') = {$type}");
        }

        return $query;
    }

    public function afterSave(int $schemeId,array $data): void
    {
        if($data['cfg']['type'] == 1){
            //多客户
            $roomCnf = $data['cfg']['room_cnf'];
            $group_pull_data = $roomCnf['group_pull_data'];
            //群满后用户退群是否进行替补
            $activeRoomData = [];
            foreach ($group_pull_data as $k=>$item){
                $activeRoomData[] = [
                    'scheme_id' => $schemeId,
                    'scheme_type' => RoomInviteLogTypeConstants::TYPE_KEYWORD_MULTI,
                    'room_wxid' => $item['crowd_id'],
                    'genders' => json_encode($item['genders']),
                    'sort' => $item['sort'],
                    'created_at' => Carbon::now()->toDateTimeString(),
                    'updated_at' => Carbon::now()->toDateTimeString()
                ];
            }

            ChRoomInviteActiveRoom::insert($activeRoomData);
        }
    }

    public function afterUpdate(int $schemeId,array $data): void
    {
        if($data['cfg']['type'] == 1){
            $existingActiveRoomMap = ChRoomInviteActiveRoom::query()
                ->where('scheme_id', $schemeId)
                ->where('scheme_type',RoomInviteLogTypeConstants::TYPE_KEYWORD_MULTI)
                ->pluck('id','room_wxid')
                ->toArray();

            //查询出已存在的
            $roomCnf = $data['cfg']['room_cnf'];
            $group_pull_data = $roomCnf['group_pull_data'];

            $toUpdate = [];
            $toInsert = [];


            foreach ($group_pull_data as $item){
                $activeRoomData = [
                    'scheme_id' => $schemeId,
                    'scheme_type' => RoomInviteLogTypeConstants::TYPE_KEYWORD_MULTI,
                    'room_wxid' => $item['crowd_id'],
                    'genders' => json_encode($item['genders']),
                    'sort' => $item['sort'],
                    'updated_at' => Carbon::now()->toDateTimeString()
                ];
                if(isset($existingActiveRoomMap[$item['crowd_id']])){
                    $activeRoomData['id'] = $existingActiveRoomMap[$item['crowd_id']];
                    $toUpdate[] = $activeRoomData;
                }else{
                    $activeRoomData['created_at'] = Carbon::now()->toDateTimeString();
                    $toInsert[] = $activeRoomData;
                }
            }
            if(!empty($toUpdate)){
                ChRoomInviteActiveRoom::upsert($toUpdate,'id');
            }
            if(!empty($toInsert)){
                ChRoomInviteActiveRoom::insert($toInsert);
            }

            $existingActiveRoomIds = collect($existingActiveRoomMap)->values()->toArray();
            $toUpdateIds = array_column($toUpdate,'id');
            $needToDelIds = array_diff($existingActiveRoomIds,$toUpdateIds);
            if(!empty($needToDelIds)){
                ChRoomInviteActiveRoom::query()
                    ->whereIn('id',$needToDelIds)
                    ->delete();
            }
        }else{
            $exists = ChRoomInviteActiveRoom::query()
                ->where('scheme_id',$schemeId)
                ->where('scheme_type',$this->type)
                ->exists();
            if($exists){
                ChRoomInviteActiveRoom::query()
                    ->where('scheme_id',$schemeId)
                    ->where('scheme_type',$this->type)
                    ->delete();
            }
        }
    }

    /**
     * 获取详情
     * @param array $params
     * @return Model|ChOpScheme|string|Builder|null
     */
    public function getInfo(array $params): Model|ChOpScheme|string|Builder|null
    {
        $info = $this->mapper->findById($params['id']);

        if(empty($info)){
            throw new NormalStatusException('请选择方案');
        }

        $cfg = $info->cfg;

        if($cfg['type'] == 0){
            $fixedMembers = $cfg['fixed_members'];
            $fixedMemberList = [];
            foreach ($fixedMembers as $fixedMember){
                $robotInfo = $this->robotMapper->findById($fixedMember['robot_id']);
                if(!empty($robotInfo)){
                    $memberNicknames = ChContact::query()
                        ->where('robot_id',$fixedMember['robot_id'])
                        ->whereIn('user_id',$fixedMember['user_ids'])
                        ->pluck('nickname')
                        ->toArray();
                    $fixedMemberList[] = [
                        'robot_id' => $robotInfo->id,
                        'robot_nickname' => $robotInfo->nickname,
                        'robot_avatar' => $robotInfo->avatar,
                        'robot_user_id' => $robotInfo->user_id,
                        'contact_name' => implode(',',$memberNicknames)
                    ];
                }
            }
            $cfg['fixed_member_list'] = $fixedMemberList;

            $cfg['employee_list'] = [];
            if(!empty($cfg['employee_user_ids'])){
                $employeeUserIds = $cfg['employee_user_ids'];
                $cfg['employee_list'] = ChEmployee::query()
                    ->select(['id','nickname','real_name','avatar_url','corp_name','user_id'])
                    ->where('main_uid',$params['main_uid'])
                    ->whereIn('user_id',$employeeUserIds)
                    ->get()->toArray();
            }
        }else{
            //多客户
            $roomCfg = $cfg['room_cnf'];

            $group_pull_data = $roomCfg['group_pull_data'];

            $crowd_id = array_column($group_pull_data,'crowd_id');

            $roomList = ChRoom::query()
                ->select(['room_wxid','room_name','room_avatar_url'])
                ->where('main_uid',$params['main_uid'])
                ->whereIn('room_wxid',$crowd_id)
                ->get()->toArray();

            $roomListMap = array_column($roomList,null,'room_wxid');

            foreach ($group_pull_data as $k=>$item){
                $room = $roomListMap[$item['crowd_id']] ?? [];
                if(!empty($room)){
                    $group_pull_data[$k]['room_name'] = $room['room_name'];
                    $group_pull_data[$k]['room_avatar_url'] = $room['room_avatar_url'];
                }else{
                    unset($group_pull_data[$k]);
                }
            }

            $groupMembers = $roomCfg['group_members'];
            $groupMemberList =[];
            foreach ($groupMembers as $groupMember){
                $robotInfo = $this->robotMapper->findById($groupMember['robot_id']);
                $memberNicknames = ChContact::query()
                    ->where('robot_id',$groupMember['robot_id'])
                    ->whereIn('user_id',$groupMember['user_ids'])
                    ->pluck('nickname')
                    ->toArray();
                $groupMemberList[] = [
                    'robot_id' => $robotInfo->id,
                    'robot_nickname' => $robotInfo->nickname,
                    'robot_avatar' => $robotInfo->avatar,
                    'robot_user_id' => $robotInfo->user_id,
                    'contact_name' => implode(',',$memberNicknames)
                ];
            }
            $roomCfg['group_pull_data'] = $group_pull_data;
            $roomCfg['group_member_list'] = $groupMemberList;
            $roomCfg['employee_list'] = [];
            if(!empty($roomCfg['employee_user_ids'])){
                $employeeUserIds = $roomCfg['employee_user_ids'];
                $roomCfg['employee_list'] = ChEmployee::query()
                    ->select(['id','nickname','real_name','avatar_url','corp_name','user_id'])
                    ->where('main_uid',$params['main_uid'])
                    ->whereIn('user_id',$employeeUserIds)
                    ->get()->toArray();
            }

            $cfg['room_cnf'] = $roomCfg;

        }
        $info->cfg = $cfg;
        return $info;
    }

    /**
     * @param array $params
     * @return array
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function getActiveRoomPageList(array $params): array
    {
        $params['scheme_type'] = RoomInviteLogTypeConstants::TYPE_KEYWORD_MULTI;

        $schemeInfo = $this->mapper->findById($params['scheme_id']);
        if(empty($schemeInfo)){
            throw new NormalStatusException('请选择方案');
        }

        $cfg = $schemeInfo->cfg;
        if($cfg['type'] == 0){
            throw new NormalStatusException('单客户模式暂不支持');
        }

        $group_user_count = $cfg['room_cnf']['group_user_count'];
        $params['group_user_count'] = $group_user_count;

        return container()->get(ChRoomInviteActiveRoomService::class)->getActiveRoomPageList($params);
    }

    /**
     * 设置进粉群状态
     * @param array $params
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function setActiveRoomStatus(array $params): bool
    {
        return container()->get(ChRoomInviteActiveRoomService::class)->setActiveRoomStatus($params,RoomInviteLogTypeConstants::TYPE_KEYWORD_MULTI);
    }

    /**
     * 删除方案
     * @param mixed $id
     * @return bool
     * @throws \Exception
     */
    #[DeleteCache("ch_op_scheme:id_#{id}"),Transaction]
    public function deleteScheme(mixed $id): bool
    {
        $scheme = $this->mapper->model::query()->find($id);
        if ($scheme) {
            ChOpSchemeRobot::query()->where('scheme_id',$id)->delete();
            $scheme->delete();

            //删除邀请日志
            ChRoomInviteLog::query()
                ->where('scheme_id',$id)
                ->whereIn('type',[RoomInviteLogTypeConstants::TYPE_KEYWORD_SINGLE,RoomInviteLogTypeConstants::TYPE_KEYWORD_MULTI])
                ->delete();

            //删除邀请发送任务
            ChRoomInviteSendTask::query()
                ->where('scheme_id',$id)
                ->whereIn('scheme_type',[RoomInviteLogTypeConstants::TYPE_KEYWORD_SINGLE,RoomInviteLogTypeConstants::TYPE_KEYWORD_MULTI])
                ->delete();

            //删除生效群
            ChRoomInviteActiveRoom::query()
                ->where('scheme_id',$id)
                ->where('scheme_type',RoomInviteLogTypeConstants::TYPE_KEYWORD_MULTI)
                ->delete();
        }
        return true;
    }

    /**
     * 获取满足条件的方案
     * @param array $data
     * @return void
     */
    public function getMeetTheConditionScheme(array $data): void
    {
        $lock = lock('room_keyword_create_lock'.json_encode($data),10);
        try {
            $lock->block(8);
            $userId = (string)$data['user_id'];
            $content = $data['content'];

            $robotInfo = $data['robotInfo'];

            $robotSchemeList = $this->schemeRobotMapper->findRobotScheme($robotInfo['id'],OpSchemeTypeConstants::ROOM_KEYWORD);

            $sendConfig = container()->get(ChSendConfigService::class)->getConfig(SendConfigConstants::ROOM_KEYWORD,$robotInfo['main_uid'],$robotInfo['id'],true);
            $needToSleep = is_sleep_needed($sendConfig['sleep_period_switch'],$sendConfig['sleep_period_cfg']);
            if($needToSleep){
                return;
            }

            foreach ($robotSchemeList as $k=>$robotScheme){
                if(empty($robotScheme->scheme)){
                    continue;
                }
                $cfg = $robotScheme->scheme->cfg;
                $triggerType = data_get($cfg,'trigger_type',2);
                if($triggerType == 0 && $data['is_robot'] != 0){
                    //仅好友发送的情况
                    continue;
                }elseif ($triggerType == 1 && $data['is_robot'] != 1){
                    //仅机器人发送的情况
                    continue;
                }
                if($cfg['type'] == 0){
                    $this->handleSingleCustomerScheme($robotInfo,$userId,$content,$robotScheme->scheme_id,$cfg);
                }else{
                    $this->handleMultipleCustomerScheme($robotInfo,$userId,$content,$robotScheme->scheme_id,$cfg);
                }
            }
        } catch (LockTimeoutException $e) {
            return;
        } finally {
            $lock->release();
        }
    }

    /**
     * 处理单人关键词拉群
     * @param array $robot
     * @param string $userId
     * @param String $content
     * @param int $schemeId
     * @param array $config
     * @return void
     */
    private function handleSingleCustomerScheme(array $robot,string $userId,String $content,int $schemeId,array $config): void
    {
        //固定群成员
        $fixedMembers = $config['fixed_members'];
        $keywords = $config['keywords'];
        //判断内容是否包含关键词
        if(!$this->checkKeywords($content,$keywords)){
            return;
        }

        $fixedMembersUserIds = [];
        foreach ($fixedMembers as $item){
            $fixedMembersUserIds = array_merge($fixedMembersUserIds,$item['user_ids']);
        }

        //固定企业成员
        if(!empty($config['employee_user_ids'])){
            $fixedMembersUserIds = array_merge($fixedMembersUserIds,$config['employee_user_ids']);
        }

        $dayLimit = $config['day_limit'];
        $roomName = $config['room_name'];

        $contactInfo = ChContact::query()
            ->select(['id','nickname','remark'])
            ->where('robot_id',$robot['id'])
            ->where('user_id',$userId)
            ->first();
        if(empty($contactInfo)){
            return;
        }

        if(!empty($contactInfo->call_name)){
            $name = $contactInfo->call_name;
        }else{
            $name = $contactInfo->nickname;
        }

        //设置群名称
        $roomName = TagReplacer::replaceTags($roomName,[
            'call_name_nickname' => $name,
            'remark' => $contactInfo->remark
        ]);
        container()->get(LowQueueService::class)->push(new CommonJob(new CommonJobDto(
            classname: RoomInviteService::class,
            method: 'createRoom',
            data:[
                'robot_id' => $robot['id'],
                'user_id' => $userId,
                'fixed_members' => $fixedMembersUserIds,
                'room_name' => $roomName,
                'day_limit' => $dayLimit,
                'scheme_id' => $schemeId,
                'type' => RoomInviteLogTypeConstants::TYPE_KEYWORD_SINGLE,
                'isSingleCustomer' => true
            ]
        )));
    }

    /**
     * 多客户关键词拉群方案
     * @param array $robot
     * @param string $userId
     * @param String $content
     * @param int $schemeId
     * @param array $config
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    private function handleMultipleCustomerScheme(array $robot,string $userId,String $content,int $schemeId,array $config): void
    {
        //关键词
        $keywords = $config['keywords'];
        //判断内容是否包含关键词
        if(!$this->checkKeywords($content,$keywords)){
            return;
        }
        //群配置
        $roomCnf = $config['room_cnf'];
        $roomCnf['invite_guide_switch'] = $config['invite_guide_switch'];
        $roomCnf['guide_text'] = $config['guide_text'];
        $lock = lock('multiple_customer_scheme_lock:'.md5($robot['id'].$userId.$schemeId),4);
        try {
            $lock->block(2);
            container()->get(RoomInviteService::class)->inviteRoomMember($schemeId,$robot['id'],$roomCnf,$userId,RoomInviteLogTypeConstants::TYPE_KEYWORD_MULTI);
        }catch (LockTimeoutException $e){

        } finally {
            optional($lock)->release();
        }
    }

    /**
     * 检查内容是否包含关键词
     * @param string $content
     * @param array $keywords
     * @return bool
     */
    private function checkKeywords(string $content,array $keywords): bool
    {
        //判断内容是否包含关键词
        $isConditionMet = false;
        foreach($keywords as $keyword){
            if(str_contains($content,$keyword)){
                $isConditionMet = true;
                break;
            }
        }

        return $isConditionMet;
    }

}